#include <fstream>

#include "dcmtk/dcmdata/dcdeftag.h"
#include "dcmtk/dcmdata/dcfilefo.h"
#include "dcmtk/dcmdata/dctk.h"
#include "dcmtk/dcmdata/dcjson.h"
#include "nlohmann/json.hpp"

#include "util.h"

#include "dataset.h"


using json = nlohmann::ordered_json;

//private field
#define PRIVATE_CREATORNAME_MARVELSTONE          "marvelstone"
#define PRIVATE_CREATOR_MARVELSTONE              0x0029,0x0010
#define PRIVATE_RDFDATAFORMAT                    0x0029,0x1000
#define PRIVATE_RDFPARAMETER                     0x0029,0x1001
#define PRIVATE_SCANID                           0x0029,0x1002
/*
mr_iod.json example:
"PRIVATE_CREATORNAME_MARVELSTONE": {
        "PRIVATE_CREATOR_MARVELSTONE": "0029,0010",
        "PRIVATE_RDFDATAFORMAT": "0029,1000",
        "PRIVATE_RDFPARAMETER": "0029,1001",
        "PRIVATE_SCANID": "0029,1002"
    }
*/

DataSet::DataSet()
{
    myDataSet = nullptr;
    //register private field, Manual maintenance
    DcmDataDictionary& dict = dcmDataDict.wrlock();
    dict.addEntry(new DcmDictEntry(PRIVATE_RDFDATAFORMAT, EVR_US, "RDFDataFormat", 1, 1, "private", true, PRIVATE_CREATORNAME_MARVELSTONE));
    dict.addEntry(new DcmDictEntry(PRIVATE_RDFPARAMETER, EVR_LT, "RDFParameter", 1, 1, "private", true, PRIVATE_CREATORNAME_MARVELSTONE));
    dict.addEntry(new DcmDictEntry(PRIVATE_SCANID, EVR_LT, "ScanID", 1, 1, "private", true, PRIVATE_CREATORNAME_MARVELSTONE));
    dcmDataDict.wrunlock();
}

DataSet::~DataSet()
{
    delete myDataSet;
}

DcmDataset*
DataSet::GetDataSet()
{
    return myDataSet;
}

bool
DataSet::LoadDCMFile(
    const std::string& aFilePath
)
{
    DcmFileFormat file;
    if (file.loadFile(OFFilename(aFilePath)) != EC_Normal) {
        std::cout << "DicomFileFormat load file [" + aFilePath + "] failed" << std::endl;
        return false;
    }
    DcmDataset* dataSet = file.getDataset();
    myDataSet = new DcmDataset(*dataSet);

    DcmObject* obj = myDataSet->nextInContainer(nullptr);
    if (nullptr == obj) {
        std::cout << "DataSet file content load failed" << std::endl;
        return false;
    }
    while (obj) {
        DcmTag tag = obj->getTag();
        myTags[tag.getTagName()] = { tag.getGTag(), tag.getETag() };
        obj = myDataSet->nextInContainer(obj);
    }
    //get private field, Manual maintenance
    myTags["PRIVATE_CREATOR_MARVELSTONE"] = { 0x0029,0x0010 };
    myTags["PRIVATE_RDFDATAFORMAT"] = { 0x0029,0x1000 };
    myTags["PRIVATE_RDFPARAMETER"] = { 0x0029,0x1001 };
    myTags["PRIVATE_SCANID"] = { 0x0029,0x1002 };


    return true;
}

bool
DataSet::ParseIODString(
    const std::string& aJsonString
)
{
    try {
        json tmp = json::parse(aJsonString);
    } catch (nlohmann::json::exception& e) {
        std::cout << "wrong json string" << std::endl;
        return false;
    }

    myDataSet = new DcmDataset();

    PrivSubParseIODFile(aJsonString);

    return true;
}

void
DataSet::PrivSubParseIODFile(
    const std::string& aJsonStr
)
{
    json jsonObj = json::parse(aJsonStr);
    if (jsonObj.is_primitive()) {
        return;
    }

    for (json::iterator it = jsonObj.begin(); it != jsonObj.end(); ++it) {
        if (json::value_t::string == it->type()) {
            Uint16 tagGroup = -1, tagElement = -1;
            std::string tagStr = it.value();
            size_t splitIndex = tagStr.find(",");
            std::string groupStr = tagStr.substr(0, splitIndex);
            std::string elementStr = tagStr.substr(splitIndex + 1, tagStr.size());
            //tagGroup
            std::stringstream groupStream;
            groupStream.str(groupStr);
            groupStream >> std::hex >> tagGroup;
            //tagElement
            std::stringstream elementStream;
            elementStream.str(elementStr);
            elementStream >> std::hex >> tagElement;
            //insert element
            DcmTag tag;
            unsigned short tagGroup29 = 0x0029;
            unsigned short tagElement29 = 0x0010;
            if (tagGroup29 == tagGroup && tagElement29 != tagElement) {
                tag = DcmTag(tagGroup, tagElement, PRIVATE_CREATORNAME_MARVELSTONE);
            } else {
                tag = DcmTag(tagGroup, tagElement);
            }
            if (EVR_px == tag.getEVR()) {
                tag.setVR(EVR_PixelData);
            }
            if (myDataSet->insertEmptyElement(tag) != EC_Normal) {
                std::cout << "insertEmptyElement() failed" << std::endl;
                return;
            }
            myTags[it.key()] = { tagGroup,tagElement };
        } else {
            PrivSubParseIODFile(jsonObj[it.key()].dump());
        }
    }
}

bool
DataSet::GeneralDCMFile(
    const std::string& aFilePath,
    DCM_TransferSyntax aXfer
)
{
    E_TransferSyntax xfer;
    if (DCM_TransferSyntax::EXS_LittleEndianExplicit == aXfer) {
        xfer = E_TransferSyntax::EXS_LittleEndianExplicit;
    } else if (DCM_TransferSyntax::EXS_LittleEndianImplicit == aXfer) {
        xfer = E_TransferSyntax::EXS_LittleEndianImplicit;
    }

    DcmFileFormat file(myDataSet);
    if (file.saveFile(OFFilename(aFilePath), xfer) != EC_Normal) {
        std::cout << "saveFile() failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::Set(
    const std::string& aFieldName,
    const std::string& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (const std::out_of_range& e) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertOFStringArray(DcmTag(tagGroup, tagElement), aValue) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::Set(
    const std::string& aFieldName,
    const unsigned short aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertUint16(DcmTag(tagGroup, tagElement), aValue) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::Set(
    const std::string& aFieldName,
    const unsigned char* aValue,
    const unsigned long aCount
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertUint8Array(DcmTag(tagGroup, tagElement), aValue, aCount) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::Set(
    const std::string& aFieldName,
    const unsigned short* aValue,
    const unsigned long aCount
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertUint16Array(DcmTag(tagGroup, tagElement), aValue, aCount) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::Set(
    const std::string& aFieldName
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertOFStringArray(DcmTag(tagGroup, tagElement), Util::GenerateUid()) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::Set(
    const std::string& aFieldName,
    const double aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertFloat64(DcmTag(tagGroup, tagElement), aValue) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::Set(
    const std::string& aFieldName,
    const float aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertFloat32(DcmTag(tagGroup, tagElement), aValue) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::Set(
    const std::string& aFieldName,
    const signed short aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertSint16(DcmTag(tagGroup, tagElement), aValue) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::Set(
    const std::string& aFieldName,
    const signed int aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertSint32(DcmTag(tagGroup, tagElement), aValue) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::Set(
    const std::string& aFieldName,
    const unsigned int aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertUint32(DcmTag(tagGroup, tagElement), aValue) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::Set(
    const std::string& aFieldName,
    const signed short* aValue,
    const unsigned long aCount
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertSint16Array(DcmTag(tagGroup, tagElement), aValue, aCount) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::Set(
    const std::string& aFieldName,
    const unsigned int* aValue,
    const unsigned long aCount
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertUint32Array(DcmTag(tagGroup, tagElement), aValue, aCount) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::Set(
    const std::string& aFieldName,
    const float* aValue,
    const unsigned long aCount
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertFloat32Array(DcmTag(tagGroup, tagElement), aValue, aCount) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::Set(
    const std::string& aFieldName,
    const double* aValue,
    const unsigned long aCount
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertFloat64Array(DcmTag(tagGroup, tagElement), aValue, aCount) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::SetPrivate(
    const std::string& aFieldName,
    const std::string& aPrivateName,
    const std::string& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertOFStringArray(DcmTag(tagGroup, tagElement, aPrivateName.c_str()), aValue) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::SetPrivate(
    const std::string& aFieldName,
    const std::string& aPrivateName,
    const unsigned short aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertUint16(DcmTag(tagGroup, tagElement, aPrivateName.c_str()), aValue) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::SetPrivate(
    const std::string& aFieldName,
    const std::string& aPrivateName
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertOFStringArray(DcmTag(tagGroup, tagElement), aPrivateName) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::SetPrivate(
    const std::string& aFieldName,
    const std::string& aPrivateName,
    const float aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertFloat32(DcmTag(tagGroup, tagElement, aPrivateName.c_str()), aValue) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::SetPrivate(
    const std::string& aFieldName,
    const std::string& aPrivateName,
    const signed short aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertSint16(DcmTag(tagGroup, tagElement, aPrivateName.c_str()), aValue) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::SetPrivate(
    const std::string& aFieldName,
    const std::string& aPrivateName,
    const signed int aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertSint32(DcmTag(tagGroup, tagElement, aPrivateName.c_str()), aValue) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::SetPrivate(
    const std::string& aFieldName,
    const std::string& aPrivateName,
    const unsigned int aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertUint32(DcmTag(tagGroup, tagElement, aPrivateName.c_str()), aValue) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::SetPrivate(
    const std::string& aFieldName,
    const std::string& aPrivateName,
    const signed short* aValue,
    const unsigned long aCount
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertSint16Array(DcmTag(tagGroup, tagElement, aPrivateName.c_str()), aValue, aCount) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::SetPrivate(
    const std::string& aFieldName,
    const std::string& aPrivateName,
    const unsigned int* aValue,
    const unsigned long aCount
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertUint32Array(DcmTag(tagGroup, tagElement, aPrivateName.c_str()), aValue, aCount) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::SetPrivate(
    const std::string& aFieldName,
    const std::string& aPrivateName,
    const float* aValue,
    const unsigned long aCount
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertFloat32Array(DcmTag(tagGroup, tagElement, aPrivateName.c_str()), aValue, aCount) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::SetPrivate(
    const std::string& aFieldName,
    const std::string& aPrivateName,
    const double* aValue,
    const unsigned long aCount
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertFloat64Array(DcmTag(tagGroup, tagElement, aPrivateName.c_str()), aValue, aCount) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::SetPrivate(
    const std::string& aFieldName,
    const std::string& aPrivateName,
    const unsigned char* aValue,
    const unsigned long aCount
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertUint8Array(DcmTag(tagGroup, tagElement, aPrivateName.c_str()), aValue, aCount) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::SetPrivate(
    const std::string& aFieldName,
    const std::string& aPrivateName,
    const unsigned short* aValue,
    const unsigned long aCount
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertUint16Array(DcmTag(tagGroup, tagElement, aPrivateName.c_str()), aValue, aCount) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::SetPrivate(
    const std::string& aFieldName,
    const std::string& aPrivateName,
    const double aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "can't support set this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    DcmElement* element = nullptr;
    if (myDataSet->findAndGetElement(DcmTagKey(tagGroup, tagElement), element) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }
    if (myDataSet->putAndInsertFloat64(DcmTag(tagGroup, tagElement, aPrivateName.c_str()), aValue) != EC_Normal) {
        std::cout << "insert [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::Get(
    const std::string& aFieldName,
    float& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "the dataset without this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    if (myDataSet->findAndGetFloat32(DcmTagKey(tagGroup, tagElement), aValue) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::Get(
    const std::string& aFieldName,
    double& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "the dataset without this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    if (myDataSet->findAndGetFloat64(DcmTagKey(tagGroup, tagElement), aValue) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::Get(
    const std::string& aFieldName,
    unsigned int& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "the dataset without this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    if (myDataSet->findAndGetUint32(DcmTagKey(tagGroup, tagElement), aValue) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::Get(
    const std::string& aFieldName,
    unsigned short& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "the dataset without this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    if (myDataSet->findAndGetUint16(DcmTagKey(tagGroup, tagElement), aValue) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::Get(
    const std::string& aFieldName,
    signed short& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "the dataset without this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    if (myDataSet->findAndGetSint16(DcmTagKey(tagGroup, tagElement), aValue) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::Get(
    const std::string& aFieldName,
    std::string& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "the dataset without this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    if (myDataSet->findAndGetOFStringArray(DcmTagKey(tagGroup, tagElement), aValue) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::Get(
    const std::string& aFieldName,
    signed int& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "the dataset without this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    if (myDataSet->findAndGetSint32(DcmTagKey(tagGroup, tagElement), aValue) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::Get(
    const std::string& aFieldName,
    const unsigned char*& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "the dataset without this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    if (myDataSet->findAndGetUint8Array(DcmTagKey(tagGroup, tagElement), aValue) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::Get(
    const std::string& aFieldName,
    const float*& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "the dataset without this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    if (myDataSet->findAndGetFloat32Array(DcmTagKey(tagGroup, tagElement), aValue) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::Get(
    const std::string& aFieldName,
    const double*& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "the dataset without this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    if (myDataSet->findAndGetFloat64Array(DcmTagKey(tagGroup, tagElement), aValue) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::Get(
    const std::string& aFieldName,
    const unsigned int*& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "the dataset without this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    if (myDataSet->findAndGetUint32Array(DcmTagKey(tagGroup, tagElement), aValue) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::Get(
    const std::string& aFieldName,
    const unsigned short*& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "the dataset without this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    if (myDataSet->findAndGetUint16Array(DcmTagKey(tagGroup, tagElement), aValue) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::Get(
    const std::string& aFieldName,
    const signed short*& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "the dataset without this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    if (myDataSet->findAndGetSint16Array(DcmTagKey(tagGroup, tagElement), aValue) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::GetPrivate(
    const std::string& aFieldName,
    std::string& aPrivateCreator,
    std::string& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "the dataset without this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    if (myDataSet->findAndGetOFStringArray(DcmTag(tagGroup, tagElement, aPrivateCreator.c_str()), aValue) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::GetPrivate(
    const std::string& aFieldName,
    std::string& aPrivateCreator,
    unsigned short& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "the dataset without this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    if (myDataSet->findAndGetUint16(DcmTag(tagGroup, tagElement, aPrivateCreator.c_str()), aValue) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::GetPrivate(
    const std::string& aFieldName,
    std::string& aPrivateCreator,
    float& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "the dataset without this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    if (myDataSet->findAndGetFloat32(DcmTag(tagGroup, tagElement, aPrivateCreator.c_str()), aValue) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::GetPrivate(
    const std::string& aFieldName,
    std::string& aPrivateCreator,
    double& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "the dataset without this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    if (myDataSet->findAndGetFloat64(DcmTag(tagGroup, tagElement, aPrivateCreator.c_str()), aValue) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::GetPrivate(
    const std::string& aFieldName,
    std::string& aPrivateCreator,
    unsigned int& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "the dataset without this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    if (myDataSet->findAndGetUint32(DcmTag(tagGroup, tagElement, aPrivateCreator.c_str()), aValue) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::GetPrivate(
    const std::string& aFieldName,
    std::string& aPrivateCreator,
    signed short& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "the dataset without this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    if (myDataSet->findAndGetSint16(DcmTag(tagGroup, tagElement, aPrivateCreator.c_str()), aValue) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::GetPrivate(
    const std::string& aFieldName,
    std::string& aPrivateCreator,
    signed int& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "the dataset without this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    if (myDataSet->findAndGetSint32(DcmTag(tagGroup, tagElement, aPrivateCreator.c_str()), aValue) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::GetPrivate(
    const std::string& aFieldName,
    std::string& aPrivateCreator,
    const unsigned char*& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "the dataset without this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    if (myDataSet->findAndGetUint8Array(DcmTag(tagGroup, tagElement, aPrivateCreator.c_str()), aValue) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::GetPrivate(
    const std::string& aFieldName,
    std::string& aPrivateCreator,
    const float*& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "the dataset without this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    if (myDataSet->findAndGetFloat32Array(DcmTag(tagGroup, tagElement, aPrivateCreator.c_str()), aValue) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::GetPrivate(
    const std::string& aFieldName,
    std::string& aPrivateCreator,
    const double*& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "the dataset without this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    if (myDataSet->findAndGetFloat64Array(DcmTag(tagGroup, tagElement, aPrivateCreator.c_str()), aValue) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::GetPrivate(
    const std::string& aFieldName,
    std::string& aPrivateCreator,
    const unsigned int*& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "the dataset without this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    if (myDataSet->findAndGetUint32Array(DcmTag(tagGroup, tagElement, aPrivateCreator.c_str()), aValue) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::GetPrivate(
    const std::string& aFieldName,
    std::string& aPrivateCreator,
    const unsigned short*& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "the dataset without this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    if (myDataSet->findAndGetUint16Array(DcmTag(tagGroup, tagElement, aPrivateCreator.c_str()), aValue) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}

bool
DataSet::GetPrivate(
    const std::string& aFieldName,
    std::string& aPrivateCreator,
    const signed short*& aValue
)
{
    unsigned short tagGroup = 0, tagElement = 0;
    try {
        tagGroup = myTags[aFieldName].at(0);
        tagElement = myTags[aFieldName].at(1);
    } catch (...) {
        std::cout << "the dataset without this field [" + aFieldName + "]" << std::endl;
        return false;
    }

    if (myDataSet->findAndGetSint16Array(DcmTag(tagGroup, tagElement, aPrivateCreator.c_str()), aValue) != EC_Normal) {
        std::cout << "find [" + aFieldName + "] failed" << std::endl;
        return false;
    }

    return true;
}
